package com.gzx.plugin.tjzy.modular.call.pre.template;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gzx.plugin.tjzy.modular.call.ht.entity.GzxHtUser;
import com.gzx.plugin.tjzy.modular.call.ht.mapper.GzxHtUserMapper;
import com.gzx.plugin.tjzy.modular.complaint.service.GzxComplaintUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.util.CommonCryptogramUtil;

import java.util.*;

/**
 * @author zjt
 * @description
 * @date 2024/11/11 10:11
 */
@Slf4j
public abstract class HtPreCallTemplateMethod {


    @Value("${call.ht.loginName}")
    private String loginName;

    @Value("${call.ht.password}")
    private String password;

    @Value("${call.ht.task-add-url}")
    private String taskAddUrl;

    @Value("${call.ht.task-addTo-url}")
    private String taskAddToUrl;

    @Value("${call.ht.task-switch-url}")
    private String taskSwitchUrl;

    @Value("${call.ht.task-update-url}")
    private String taskUpdateUrl;

    @Value("${call.ht.listen-voice-url.start}")
    private String listenVoiceStartUrl;

    @Value("${call.ht.listen-voice-url.stop}")
    private String listenVoiceStopUrl;

    @Value("${call.ht.callback-url.record}")
    private String recordCallBackUrl;

    @Value("${call.ht.callback-url.voice-to-text}")
    private String voiceTextCallBackUrl;

    @Value("${call.ht.listen-login-account}")
    private String listenLoginAccount;

    @Value("${call.ht.listen-login-password}")
    private String listenLoginPassword;

    @Value("${call.ht.record.sync.url}")
    private String recordSyncUrl;

    @Value("${call.ht.record.sync.tenant}")
    private String recordSyncTenant;

    @Value("${call.ht.record.sync.limit}")
    private Integer recordSyncLimit;

    @Value("${call.ht.record.sync.secret}")
    private String recordSyncSecret;

    @Resource
    private GzxHtUserMapper htUserMapper;

    @Resource
    private GzxComplaintUserService complaintUserService;

    /**
     * 准备开始预测外呼
     *
     * @return
     */
    public String startPreCall(String batchNumber, Integer callThread, String callPhone) {
        //校验是否有恒天账号，获取坐席工号
        String userName = getUserName();
        //获取手机号和透传字段
        Map<String, Long> params = getCallParams(batchNumber);
        if (CollectionUtil.isEmpty(params)) {
            return null;
        }
        //创建任务
        String taskId = createTask(callThread, userName, callPhone);
        //保存任务ID
        List<Long> idList = new ArrayList<>(params.values());
        saveTaskId(taskId, idList);
        //追加数据
        addTaskData(taskId, callPhone, params);
        //开启任务
        switchTask(taskId, 1);
        return taskId;
    }

    /**
     * 获取预测外呼参数，Key为手机号，val为透传字段
     *
     * @param batchNumber
     * @return
     */
    protected abstract Map<String, Long> getCallParams(String batchNumber);

    /**
     * 保存任务ID
     *
     * @param taskId
     * @param idList
     */
    protected abstract void saveTaskId(String taskId, List<Long> idList);

    /**
     * 创建任务
     *
     * @param callThread
     * @param userName
     * @return
     */
    private String createTask(int callThread, String userName, String callPhone) {
        log.info("调用预测外呼-任务创建...");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("LoginName", loginName);
        dataMap.put("PassWord", password);
        dataMap.put("State", "1");
        //0：多人预测外呼 1：单人预测外呼 6：机器人优先
        dataMap.put("DialType", "1");
        dataMap.put("TemplateID", "000001");
        dataMap.put("CallThreads", callThread);
        dataMap.put("DataType", "XMD");
        dataMap.put("CallPhone", callPhone);
        //坐席工号
        dataMap.put("AgentWorkid", userName);
        //请求主体信息
        String reqStr = JSON.toJSONString(dataMap);
        log.info("调用预测外呼-任务创建-入参:{}", reqStr);
        String responseJson = callRemoteApi(taskAddUrl, reqStr, null);
        log.info("调用预测外呼-任务创建-反参:{}", responseJson);
        JSONObject jsonObject = JSON.parseObject(responseJson);
        return jsonObject.get("Data").toString();
    }

    /**
     * 追加任务数据
     *
     * @param taskId
     * @param params
     * @return
     */
    private void addTaskData(String taskId, String callPhone, Map<String, Long> params) {
        if (StringUtils.isBlank(taskId)) {
            throw new CommonException("TaskId为空，任务追加失败");
        }
        List<String> phoneList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(params)) {
            List<Map<String, Object>> dataList = new ArrayList();
            for (String key : params.keySet()) {
                Map<String, Object> dataMap = new HashMap<>();
                dataMap.put("CallPhone", callPhone);
                dataMap.put("Phone", key);
                phoneList.add(key);
                //透传字段
                dataMap.put("Business", params.get(key));
                dataList.add(dataMap);
            }
            //请求主体信息
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("LoginName", loginName);
            dataMap.put("PassWord", password);
            dataMap.put("TaskId", taskId);
            dataMap.put("TemplateID", "000001");
            //0：多人预测外呼 1：单人预测外呼 6：机器人优先
            dataMap.put("DialType", "1");
            dataMap.put("CallBackUrl", recordCallBackUrl);
            dataMap.put("case", dataList);
            String reqStr = JSON.toJSONString(dataMap);
            log.info("调用预测外呼-任务数据追加-入参:{}", reqStr);
            callRemoteApi(taskAddToUrl, reqStr, null);
        }
    }

    /**
     * 关闭任务
     *
     * @param taskId
     */
    public void switchTask(String taskId, Integer type) {
        log.info("预测外呼调用恒天接口开始，任务类型--->{}", type);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("LoginName", loginName);
        dataMap.put("PassWord", password);
        dataMap.put("TaskId", taskId);
        dataMap.put("Type", type);
        String reqStr = JSON.toJSONString(dataMap);
        //请求主体信息
        log.info("预测外呼调用恒天接口结束，入参:{}", reqStr);
        callRemoteApi(taskSwitchUrl, reqStr, null);
    }

    public void changeCallee(String taskId, String caller) {
        log.info("预测外呼调用恒天接口开始，任务类型--->更换主叫");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("LoginName", loginName);
        dataMap.put("PassWord", password);
        dataMap.put("TaskId", taskId);
        dataMap.put("CallPhone", caller);
        String reqStr = JSON.toJSONString(dataMap);
        //请求主体信息
        log.info("预测外呼调用恒天接口结束，，任务类型--->更换主叫---入参:{}", reqStr);
        callRemoteApi(taskUpdateUrl, reqStr, null);
    }

    /**
     * 订阅语音文字消息
     *
     * @param agentExtNo 坐席分机号
     */
    public String startListen(String agentExtNo) {
        log.info("开始监听坐席通话，{}", agentExtNo);
        Map<String, String> reqMap = Map.of("extAgentId", agentExtNo, "callBackUrl", voiceTextCallBackUrl);
        return callRemoteApi(listenVoiceStartUrl, JSON.toJSONString(reqMap), generateListenToken());
    }

    /**
     * 取消订阅语音文字消息
     *
     * @param agentExtNo 坐席分机号
     */
    public String stopListen(String agentExtNo) {
        Map<String, String> reqMap = Map.of("extAgentId", agentExtNo);
        return callRemoteApi(listenVoiceStopUrl, JSON.toJSONString(reqMap), generateListenToken());
    }

    public void syncCallRecord() {
        //
    }

    public String getCallRecord(String beginTime, String endTime, int currentPage) {
        return syncCallRecordHttp(beginTime, endTime, currentPage);
    }

    private String generateListenToken() {
        String digestStr = CommonCryptogramUtil.doMd5(listenLoginAccount + listenLoginPassword);
        return "Basic " + Base64.getEncoder().encodeToString((listenLoginAccount + ":" + digestStr).getBytes(java.nio.charset.StandardCharsets.UTF_8));
    }

    /**
     * 请求服务
     *
     * @param url      请求地址
     * @param bodyJson 入参
     * @return jsonObject  Json对象
     */
    private String callRemoteApi(String url, String bodyJson, String token) {
        //记录接口开始时间
        long apiBeginTime = System.currentTimeMillis();
        HttpRequest post = HttpUtil.createPost(url);
        // 设定请求头
        post.header(Header.CONTENT_TYPE, "application/json");
        if (StringUtils.isNotEmpty(token)) {
            post.header(Header.AUTHORIZATION, token);
        }
        // 设定请求体
        post.body(bodyJson);
        //设置超时时间为5秒
        post.timeout(5000);
        HttpResponse execute = post.execute();
        int statusCode = execute.getStatus();
        if (statusCode == 200) {
            String body = execute.body();
            log.info("接口响应参数:{}", body);
            log.info("本次查询远端接口耗时:{}", System.currentTimeMillis() - apiBeginTime);
            return body;
        } else {
            log.error("接口返回码为{}，调用失败，我方请求报文为：{}", statusCode, post);
            return null;
        }
    }

    /**
     * 校验投诉用户
     *
     * @param idCardList
     */
    public void preCheckIsComplaintUser(List<String> idCardList) {
        List<String> complaintUserList = complaintUserService.checkComplaintUser(idCardList);
        if (CollectionUtil.isNotEmpty(complaintUserList)) {
            throw new CommonException(complaintUserList + "：为投诉用户，请先移除与其相关的案件");
        }
    }

    private String syncCallRecordHttp(String beginTime, String endTime, int offset) {
        String url = recordSyncUrl + "?offset=" + offset + "&limit=" + recordSyncLimit;
        HttpRequest httpPost = HttpUtil.createPost(url);
        httpPost.header(Header.CONTENT_TYPE, "application/json");
        long timestamp = System.currentTimeMillis();
        httpPost.header("Tenant", recordSyncTenant);
        httpPost.header("Timestamp", String.valueOf(timestamp));
        Map<String, Object> bodyEncryptMap = new HashMap<>();
        bodyEncryptMap.put("callTimeMin", beginTime);
        bodyEncryptMap.put("callTimeMax", endTime);
        String bodyText = JSON.toJSONString(bodyEncryptMap);
        String sign = recordSyncTenant + timestamp + recordSyncSecret;
        httpPost.header("Signature", CommonCryptogramUtil.doAesECBEncrypt(bodyText, sign));
        httpPost.body(bodyText);
        String body = "";
        try (HttpResponse execute = httpPost.execute()) {
            body = execute.body();
        } catch (Exception e) {
            log.error("调用查询恒天话单接口出错", e);
        }
        log.info("请求地址： {}\n请求头： {}\n请求参数： {}\n请求结果： {}\n", url, httpPost.headers(), bodyText, body);
        return CommonCryptogramUtil.doAesECBDecrypt(JSONObject.parseObject(body).getString("data"), sign);
    }

    /**
     * 获取当前登录者的恒天账号
     *
     * @return
     */
    private String getUserName() {
        //判断是否是调解员
        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
//        Set<String> permissionSet = loginUser.getRolePermission();
//        if (!permissionSet.contains("tjuser")) {
//            throw new ServiceException("无预测外呼权限");
//        }
        GzxHtUser htUser = htUserMapper.selectOne(Wrappers.<GzxHtUser>lambdaQuery()
                .eq(GzxHtUser::getUserName, loginUser.getAccount()));
        if (htUser == null) {
            return loginUser.getAccount();
        }
        return htUser.getHtAccount();
    }
}
